#include "ZTileLayout.h"
#include "ZScrollBar.h"

namespace ZuiLib
{


	ZTileLayout::ZTileLayout() : m_nColumns(1), m_nRows(0), m_nColumnsFixed(0), m_iChildVPadding(0),
		m_bIgnoreItemPadding(true)
	{
		m_szItem.cx = m_szItem.cy = 80;
	}

	ZTileLayout::~ZTileLayout()
	{

	}

	const char* ZTileLayout::GetClass() const
	{
		return "TileLayout";
	}

	void* ZTileLayout::GetInterface(const char* pstrName)
	{
		if (strcmp(pstrName, "TileLayout") == 0) return static_cast<ZTileLayout*>(this);
		return ZContainer::GetInterface(pstrName);
	}

	int ZTileLayout::GetFixedColumns() const
	{
		return m_nColumnsFixed;
	}

	void ZTileLayout::SetFixedColumns(int iColums)
	{
		if (iColums < 0) return;
		m_nColumnsFixed = iColums;
		NeedUpdate();
	}

	int ZTileLayout::GetChildVPadding() const
	{
		return m_iChildVPadding;
	}

	void ZTileLayout::SetChildVPadding(int iPadding)
	{
		m_iChildVPadding = iPadding;
		if (m_iChildVPadding < 0) m_iChildVPadding = 0;
		NeedUpdate();
	}

	SIZE ZTileLayout::GetItemSize() const
	{
		return m_szItem;
	}

	void ZTileLayout::SetItemSize(SIZE szSize)
	{
		if (m_szItem.cx != szSize.cx || m_szItem.cy != szSize.cy) {
			m_szItem = szSize;
			NeedUpdate();
		}
	}

	int ZTileLayout::GetColumns() const
	{
		return m_nColumns;
	}

	int ZTileLayout::GetRows() const
	{
		return m_nRows;
	}

	void ZTileLayout::SetAttribute(const char* pstrName, const char* pstrValue)
	{
		if (strcmp(pstrName,"itemsize") == 0) {
			SIZE szItem = { 0 };
            ParserSize(&szItem, pstrValue);
			SetItemSize(szItem);
		}
		else if (strcmp(pstrName, "columns") == 0) 
            SetFixedColumns(atoi(pstrValue));
		else if (strcmp(pstrName, "childvpadding") == 0) 
            SetChildVPadding(ParserSize(pstrValue));
		else 
            ZContainer::SetAttribute(pstrName, pstrValue);
	}

	void ZTileLayout::SetPos(RECT rc)
	{
		ZControl::SetPos(rc);
		rc = m_rcItem;

		// Adjust for inset
		rc.left += m_rcInset.left;
		rc.top += m_rcInset.top;
		rc.right -= m_rcInset.right;
		rc.bottom -= m_rcInset.bottom;
		if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) 
			rc.right -= m_pVerticalScrollBar->GetFixedWidth();

		if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) 
			rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight();

		if (m_items.GetSize() == 0) {
			ProcessScrollBar(rc, 0, 0);
			return;
		}

		// Determine the minimum size
		SIZE szAvailable = { rc.right - rc.left, rc.bottom - rc.top };
		if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible())
			szAvailable.cx += m_pHorizontalScrollBar->GetScrollRange();

		if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible())
			szAvailable.cy += m_pVerticalScrollBar->GetScrollRange();

		int nEstimateNum = 0;
		for (int it = 0; it < m_items.GetSize(); it++) {
			ZControl* pControl = static_cast<ZControl*>(m_items[it]);
			if (!pControl->IsVisible()) continue;
			if (pControl->IsFloat()) continue;
			nEstimateNum++;
		}

		int cxNeeded = 0;
		int cyNeeded = 0;
		int iChildPadding = m_iChildPadding;
		if (m_nColumnsFixed == 0) {
			if (rc.right - rc.left >= m_szItem.cx) {
				m_nColumns = (rc.right - rc.left) / m_szItem.cx;
				cxNeeded = rc.right - rc.left;
				if (m_nColumns > 1) {
					if (iChildPadding <= 0) {
						iChildPadding = (cxNeeded - m_nColumns*m_szItem.cx) / (m_nColumns - 1);
					}
					if (iChildPadding < 0) iChildPadding = 0;
				}
				else {
					iChildPadding = 0;
				}
			}
			else {
				m_nColumns = 1;
				cxNeeded = m_szItem.cx;
			}

			m_nRows = (nEstimateNum - 1) / m_nColumns + 1;
			cyNeeded = m_nRows*m_szItem.cy + (m_nRows - 1)*m_iChildVPadding;
		}
		else {
			m_nColumns = m_nColumnsFixed;
			if (m_nColumns > 1) {
				if (iChildPadding <= 0) {
					if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() && 
						rc.right - rc.left >= m_nColumns*m_szItem.cx) {
						iChildPadding = (rc.right - rc.left - m_nColumns*m_szItem.cx) / (m_nColumns - 1);
					}
					else {
						iChildPadding = (szAvailable.cx - m_nColumns*m_szItem.cx) / (m_nColumns - 1);
					}
				}
				if (iChildPadding < 0) iChildPadding = 0;
			}
			else 
				iChildPadding = 0;

			if (nEstimateNum >= m_nColumns) 
				cxNeeded = m_nColumns*m_szItem.cx + (m_nColumns - 1)*iChildPadding;
			else 
				cxNeeded = nEstimateNum*m_szItem.cx + (nEstimateNum - 1)*iChildPadding;
			m_nRows = (nEstimateNum - 1) / m_nColumns + 1;
			cyNeeded = m_nRows*m_szItem.cy + (m_nRows - 1)*m_iChildVPadding;
		}

		for (int it1 = 0; it1 < m_items.GetSize(); it1++) {
			ZControl* pControl = static_cast<ZControl*>(m_items[it1]);
			if (!pControl->IsVisible()) continue;
			if (pControl->IsFloat()) {
				SetFloatPos(it1);
				continue;
			}

			RECT rcPadding = pControl->GetPadding();
			SIZE sz = m_szItem;
			sz.cx -= rcPadding.left + rcPadding.right;
			sz.cy -= rcPadding.top + rcPadding.bottom;
			if (sz.cx > pControl->GetMaxWidth()) sz.cx = pControl->GetMaxWidth();
			if (sz.cy > pControl->GetMaxHeight()) sz.cy = pControl->GetMaxHeight();
			if (sz.cx < 0) sz.cx = 0;
			if (sz.cy < 0) sz.cy = 0;

			uint32_t iChildAlign = GetChildAlign();
			uint32_t iChildVAlign = GetChildVAlign();
			int iColumnIndex = it1 / m_nColumns;
			int iRowIndex = it1%m_nColumns;
			int iPosX = rc.left + iRowIndex*(m_szItem.cx + iChildPadding);
			if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) {
				iPosX -= m_pHorizontalScrollBar->GetScrollPos();
			}
			int iPosY = rc.top + iColumnIndex*(m_szItem.cy + m_iChildVPadding);
			if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) {
				iPosY -= m_pVerticalScrollBar->GetScrollPos();
			}
			if (iChildAlign == DT_CENTER) {
				if (iChildVAlign == DT_VCENTER) {
					RECT rcCtrl = { iPosX + (m_szItem.cx - sz.cx) / 2 + rcPadding.left, 
						iPosY + (m_szItem.cy - sz.cy) / 2 + rcPadding.top, 
						iPosX + (m_szItem.cx - sz.cx) / 2 + sz.cx - rcPadding.right, 
						iPosY + (m_szItem.cy - sz.cy) / 2 + sz.cy - rcPadding.bottom };
					pControl->SetPos(rcCtrl);
				}
				else if (iChildVAlign == DT_BOTTOM) {
					RECT rcCtrl = { iPosX + (m_szItem.cx - sz.cx) / 2 + rcPadding.left, 
						iPosY + m_szItem.cy - sz.cy + rcPadding.top, 
						iPosX + (m_szItem.cx - sz.cx) / 2 + sz.cx - rcPadding.right, 
						iPosY + m_szItem.cy - rcPadding.bottom };
					pControl->SetPos(rcCtrl);
				}
				else {
					RECT rcCtrl = { iPosX + (m_szItem.cx - sz.cx) / 2 + rcPadding.left, 
						iPosY + rcPadding.top, 
						iPosX + (m_szItem.cx - sz.cx) / 2 + sz.cx - rcPadding.right,
						iPosY + sz.cy - rcPadding.bottom };
					pControl->SetPos(rcCtrl);
				}
			}
			else if (iChildAlign == DT_RIGHT) {
				if (iChildVAlign == DT_VCENTER) {
					RECT rcCtrl = { iPosX + m_szItem.cx - sz.cx + rcPadding.left, 
						iPosY + (m_szItem.cy - sz.cy) / 2 + rcPadding.top, 
						iPosX + m_szItem.cx - rcPadding.right, 
						iPosY + (m_szItem.cy - sz.cy) / 2 + sz.cy - rcPadding.bottom };
					pControl->SetPos(rcCtrl);
				}
				else if (iChildVAlign == DT_BOTTOM) {
					RECT rcCtrl = { iPosX + m_szItem.cx - sz.cx + rcPadding.left, 
						iPosY + m_szItem.cy - sz.cy + rcPadding.top, 
						iPosX + m_szItem.cx - rcPadding.right, 
						iPosY + m_szItem.cy - rcPadding.bottom };
					pControl->SetPos(rcCtrl);
				}
				else {
					RECT rcCtrl = { iPosX + m_szItem.cx - sz.cx + rcPadding.left, 
						iPosY + rcPadding.top, 
						iPosX + m_szItem.cx - rcPadding.right, 
						iPosY + sz.cy - rcPadding.bottom };
					pControl->SetPos(rcCtrl);
				}
			}
			else {
				if (iChildVAlign == DT_VCENTER) {
					RECT rcCtrl = { iPosX + rcPadding.left, 
						iPosY + (m_szItem.cy - sz.cy) / 2 + rcPadding.top,
						iPosX + sz.cx - rcPadding.right, 
						iPosY + (m_szItem.cy - sz.cy) / 2 + sz.cy - rcPadding.bottom };
					pControl->SetPos(rcCtrl);
				}
				else if (iChildVAlign == DT_BOTTOM) {
					RECT rcCtrl = { iPosX + rcPadding.left, 
						iPosY + m_szItem.cy - sz.cy + rcPadding.top,
						iPosX + sz.cx - rcPadding.right, 
						iPosY + m_szItem.cy - rcPadding.bottom };
					pControl->SetPos(rcCtrl);
				}
				else {
					RECT rcCtrl = { iPosX + rcPadding.left, 
						iPosY + rcPadding.top, 
						iPosX + sz.cx - rcPadding.right, 
						iPosY + sz.cy - rcPadding.bottom };
					pControl->SetPos(rcCtrl);
				}
			}
		}

		// Process the scrollbar
		ProcessScrollBar(rc, cxNeeded, cyNeeded);

	}



}//namespace
